﻿using Orchard.ContentManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Extensions;
using Orchard.Widgets.Models;
using System.Collections.Generic;

namespace Vitus.Utils
{
    [OrchardFeature("Vitus.MenuAlternates")]
    public class MenuAlternates : IShapeTableProvider
    {
        public void Discover(ShapeTableBuilder builder)
        {
            builder.Describe("Parts_MenuWidget")
                .OnDisplaying(displaying =>
                {
                    ContentItem contentItem = displaying.Shape.ContentItem;

                    if (contentItem != null)
                    {
                        var menuWidget = displaying.Shape;
                        var menu = menuWidget.Menu;
                        string menuName = menu.MenuName;

                        // Parts_MenuWidget__[MenuName] e.g. Parts.MenuWidget-Main-Menu
                        displaying.ShapeMetadata.Alternates.Add("Parts_MenuWidget__" + EncodeAlternateElement(menuName));

                        var widgetPart = contentItem.As<WidgetPart>();
                        
                        if (widgetPart != null)
                        {
                            string zone = widgetPart.Zone;

                            SetShapeZone(menuWidget, zone);
                            SetShapeZone(menu, zone);

                            // Parts_MenuWidget__[ZoneName] e.g. Parts.MenuWidget-Navigation
                            displaying.ShapeMetadata.Alternates.Add("Parts_MenuWidget__" + EncodeAlternateElement(zone));

                            // Parts_MenuWidget__[MenuName]__[ZoneName] e.g. Parts.MenuWidget-Main-Menu-Navigation
                            displaying.ShapeMetadata.Alternates.Add("Parts_MenuWidget__" + EncodeAlternateElement(menuName) + "__" + EncodeAlternateElement(zone));
                        }
                    }
                });

            builder.Describe("Menu")
                .OnDisplaying(displaying =>
                {
                    var menu = displaying.Shape;
                    string menuName = menu.MenuName;
                    string zone = menu.Zone;

                    if (zone != null)
                    {
                        // Menu__[ZoneName] e.g. Menu-Navigation
                        displaying.ShapeMetadata.Alternates.Add("Menu__" + EncodeAlternateElement(zone));

                        // Menu__[MenuName]__[ZoneName] e.g. Menu-Main-Menu-Navigation
                        displaying.ShapeMetadata.Alternates.Add("Menu__" + EncodeAlternateElement(menuName) + "__" + EncodeAlternateElement(zone));
                    }
                });

            builder.Describe("MenuItem")
                .OnDisplaying(displaying =>
                {
                    var menuItem = displaying.Shape;
                    var menu = menuItem.Menu;
                    string menuName = menu.MenuName;
                    string zone = menuItem.Zone;

                    if (zone != null)
                    {
                        // MenuItem__[ZoneName] e.g. MenuItem-Navigation
                        displaying.ShapeMetadata.Alternates.Add("MenuItem__" + EncodeAlternateElement(zone));

                        // MenuItem__[MenuName]__[ZoneName] e.g. MenuItem-Main-Menu-Navigation
                        displaying.ShapeMetadata.Alternates.Add("MenuItem__" + EncodeAlternateElement(menuName) + "__" + EncodeAlternateElement(zone));
                    }
                });

            builder.Describe("MenuItemLink")
                .OnDisplaying(displaying =>
                {
                    if (displaying.Shape.Zone != null)
                    {
                        var menuItem = displaying.Shape;
                        string menuName = menuItem.Menu.MenuName;
                        string contentType = null;
                        string zone = menuItem.Zone;

                        if (menuItem.Content != null)
                        {
                            contentType = ((IContent)menuItem.Content).ContentItem.ContentType;
                        }

                        // MenuItemLink__[ZoneName] e.g. MenuItemLink-Navigation
                        displaying.ShapeMetadata.Alternates.Add("MenuItemLink__" + EncodeAlternateElement(zone));

                        // MenuItemLink__[MenuName]__[ZoneName] e.g. MenuItemLink-Main-Menu-Navigation
                        menuItem.Metadata.Alternates.Add("MenuItemLink__" + EncodeAlternateElement(menuName) + "__" + EncodeAlternateElement(zone));

                        // MenuItemLink__[ZoneName]__[ContentType] e.g. MenuItemLink-Navigation-HtmlMenuItem
                        if (contentType != null)
                        {
                            displaying.ShapeMetadata.Alternates.Add("MenuItemLink__" + EncodeAlternateElement(zone) + "__" + EncodeAlternateElement(contentType));
                        }

                        // MenuItemLink__[MenuName]__[ZoneName]__[ContentType] e.g. MenuItemLink-Main-Menu-Navigation-HtmlMenuItem
                        if (contentType != null)
                        {
                            menuItem.Metadata.Alternates.Add("MenuItemLink__" + EncodeAlternateElement(menuName) + "__" + EncodeAlternateElement(zone) + "__" + EncodeAlternateElement(contentType));
                        }
                    }
                });
        }

        private void SetShapeZone(dynamic shape, string zone)
        {
            shape.Zone = zone;

            foreach (dynamic childShape in shape.Items)
            {
                SetShapeZone(childShape, zone);
            }

            if (shape.Child != null)
            {
                SetShapeZone(shape.Child, zone);
            }
        }

        /// <summary>
        /// Encodes dashed and dots so that they don't conflict in filenames 
        /// </summary>
        /// <param name="alternateElement"></param>
        /// <returns></returns>
        private string EncodeAlternateElement(string alternateElement)
        {
            return alternateElement.Replace("-", "__").Replace(".", "_");
        }
    }
}